﻿// LSImmShiftRegOffset.cs
// Contains a class for an immediate shifted register Offset for a load store instruction

using System;

namespace armsim
{

    /// <summary>
    /// Class for a Load Store Immediate Shifted Register Offset for a Load/Store instruction
    /// </summary>
    public class LSImmShiftRegOffset : LSOffset
    {
        /// <summary>
        /// Number of places to shift by
        /// </summary>
        public uint Shift { get; protected set; }

        /// <summary>
        /// Type of shift operation
        /// </summary>
        public uint Sh { get; protected set; }

        /// <summary>
        /// Register whose value is to be shifted
        /// </summary>
        public uint Rm { get; protected set; }

        /// <summary>
        /// Intializes a new LSImmShiftRegOffset
        /// </summary>
        /// <param name="instruction">32bit instruction to be decoded</param>
        public LSImmShiftRegOffset(uint instruction) : base(instruction)
        {
            this.Shift = VirtualMemory.ExtractBits(instruction, 7, 11);
            this.Sh = VirtualMemory.ExtractBits(instruction, 5, 6);
            this.Rm = VirtualMemory.ExtractBits(instruction, 0, 3);
        }

        /// <summary>
        /// Computes the offset's value and returns it
        /// </summary>
        /// <param name="cpu">Cpu to get info from</param>
        /// <returns>the offset</returns>
        public override uint ComputeOffset(VirtualCPU cpu)
        {
            return BarrelShifter.Shift(this.Sh, cpu.Registers.ReadRegistersDuringExecute(VirtualMemory.MapRegNoToRegMem(this.Rm)), this.Shift);
        }

        /// <summary>
        /// Converts the offet to its assembly code representation
        /// </summary>
        /// <param name="cpu">grabs info form here</param>
        /// <returns>the assembly string</returns>
        public override string ToAssembly(VirtualCPU cpu)
        {
            if (IsPositive)
            {
                return Shift != 0u
                           ? String.Format(", {0}, {1}", VirtualMemory.RegToAssembly(this.Rm),
                                           BarrelShifter.ToAssembly(Sh, Shift))
                           : String.Format(", {0}", VirtualMemory.RegToAssembly(this.Rm));
            }
            else
            {
                return Shift != 0u
                           ? String.Format(", -{0}, {1}", VirtualMemory.RegToAssembly(this.Rm),
                                           BarrelShifter.ToAssembly(Sh, Shift))
                           : String.Format(", -{0}", VirtualMemory.RegToAssembly(this.Rm));
            }
        }
    }
}
